// Copyright Vanya Davidenko: MSVC, Intel С++ and gcc only.
// Используемая кодировка: UTF-8.
// (C) Copyright John Maddock 2000.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// [Vanya Davidenko]: Original:boost::static_assert.
// boost or BOOST prefixes were saved only on unchanged types/expressions.
// Tested on MSVC 8.0 (VS2005), Intel C++ 11.1.061 and g++ 4.3.2, g++ 3.44.

#ifndef LIBV_STATIC_ASSERT_H_
#define LIBV_STATIC_ASSERT_H_

// Простейшая переносимая реализация STATIC_ASSERT.
#define LIBV_SIMPLE_STATIC_ASSERT(x) extern int STATIC_ASSERTION_ERROR[x ? 1:-1]


namespace libv
{
    template<bool x> struct StaticAssertionFailure;
    template<> struct StaticAssertionFailure<true> { enum { value = 1 }; };

    template<int x> struct StaticAssertTest{};
}  // libv


// If the compiler issues warnings about old C style casts, then enable this:
#if defined(__GNUC__) && \
  ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4)))
#define LIBV_STATIC_ASSERT_BOOL_CAST(x) ((x) == 0 ? false : true)
#else
#define LIBV_STATIC_ASSERT_BOOL_CAST(x) (bool)(x)
#endif

//
// Helper macro BOOST_JOIN:
// The following piece of macro magic joins the two
// arguments together, even when one of the arguments is
// itself a macro (see 16.3.1 in C++ standard).  The key
// is that macro expansion of macro arguments does not
// occur in BOOST_DO_JOIN2 but does in BOOST_DO_JOIN.
//
#ifndef LIBV_JOIN
# define LIBV_JOIN(X,Y) BOOST_DO_JOIN(X,Y)
# define BOOST_DO_JOIN(X,Y) BOOST_DO_JOIN2(X,Y)
# define BOOST_DO_JOIN2(X,Y) X##Y
#endif  // LIBV_JOIN


#if defined(_MSC_VER) && (_MSC_VER < 1300)
// __LINE__ macro broken when -ZI is used see Q199057
// fortunately MSVC ignores duplicate typedef's.
#define LIBV_STATIC_ASSERT( B ) \
    typedef libv::StaticAssertTest<\
      sizeof(libv::StaticAssertionFailure< (bool)( B ) >)\
      > StaticAsserttypedef

#elif defined(_MSC_VER)
#define LIBV_STATIC_ASSERT( B ) \
  typedef libv::StaticAssertTest<\
    sizeof(libv::StaticAssertionFailure<LIBV_STATIC_ASSERT_BOOL_CAST(B)>)> \
      LIBV_JOIN(StaticAsserttypedef, __COUNTER__)



#elif defined(__INTEL_COMPILER) || ( defined(__GNUC__) && (__GNUC__ == 3) && \
          ( (__GNUC_MINOR__ == 3) || (__GNUC_MINOR__ == 4)) )
// agurt 15/sep/02: a special care is needed to force Intel C++ issue an error
// instead of warning in case of failure
#define LIBV_STATIC_ASSERT( B ) \
  typedef char LIBV_JOIN(StaticAsserttypedef, __LINE__) \
    [ libv::StaticAssertionFailure<LIBV_STATIC_ASSERT_BOOL_CAST(B)>::value ]


#else
// generic version
#define LIBV_STATIC_ASSERT( B ) \
  typedef libv::StaticAssertTest<\
    sizeof(libv::StaticAssertionFailure<LIBV_STATIC_ASSERT_BOOL_CAST(B)>)> \
      LIBV_JOIN(StaticAsserttypedef, __LINE__)
#endif

#endif  // LIBV_STATIC_ASSERT_H_
